package com.gitee.sop.layui.adminserver.module.background.system.api.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gitee.easyopen.annotation.Api;
import com.gitee.easyopen.doc.annotation.ApiDoc;
import com.gitee.easyopen.doc.annotation.ApiDocMethod;
import com.gitee.easyopen.util.CopyUtil;
import com.gitee.sop.layui.adminserver.module.background.system.api.isv.result.RoleVO;
import com.gitee.sop.layui.adminserver.module.background.system.api.service.param.*;
import com.gitee.sop.layui.adminserver.module.background.system.api.service.result.RouteVO;
import com.gitee.sop.layui.adminserver.module.background.system.bean.RouteConfigDto;
import com.gitee.sop.layui.adminserver.module.background.system.entity.ConfigServiceRoute;
import com.gitee.sop.layui.adminserver.module.background.system.entity.PermRole;
import com.gitee.sop.layui.adminserver.module.background.system.entity.PermRolePermission;
import com.gitee.sop.layui.adminserver.module.background.system.entity.RouteRoleDTO;
import com.gitee.sop.layui.adminserver.module.background.system.mapper.ConfigServiceRouteMapper;
import com.gitee.sop.layui.adminserver.module.background.system.mapper.PermRoleMapper;
import com.gitee.sop.layui.adminserver.module.background.system.mapper.PermRolePermissionMapper;
import com.gitee.sop.layui.adminserver.module.background.system.service.RouteConfigService;
import com.gitee.sop.layui.adminserver.module.background.system.service.RoutePermissionService;
import com.gitee.sop.layui.adminserver.module.base.constants.Result;
import com.gitee.sop.layui.adminserver.module.base.error.ServiceInterruptionException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@RestController
@ApiDoc("服务管理-路由管理")
@Slf4j
public class RouteApi {

    @Autowired
    PermRolePermissionMapper permRolePermissionMapper;

    @Autowired
    PermRoleMapper permRoleMapper;

    @Autowired
    private ConfigServiceRouteMapper configServiceRouteMapper;

    @Autowired
    RoutePermissionService routePermissionService;

    @Autowired
    RouteConfigService routeConfigService;

    @GetMapping("/api/route.page")
    @ApiDocMethod(description = "路由列表，分页")
    Result page(RouteSearchParam form) {
        Page<ConfigServiceRoute> page = new Page<>(form.getPageIndex(), form.getPageSize());
        LambdaQueryWrapper<ConfigServiceRoute> wrapper = new QueryWrapper<ConfigServiceRoute>().lambda();
        wrapper.eq(StringUtils.isNotBlank(form.getServiceId()), ConfigServiceRoute::getServiceId, form.getServiceId());
        wrapper.eq(Objects.nonNull(form.getNeedToken()), ConfigServiceRoute::getNeedToken, form.getNeedToken());
        wrapper.eq(Objects.nonNull(form.getStatus()), ConfigServiceRoute::getStatus, form.getStatus());
        wrapper.like(StringUtils.isNotBlank(form.getId()), ConfigServiceRoute::getId, form.getId());
        configServiceRouteMapper.selectPage(page, wrapper);
        List<ConfigServiceRoute> records = page.getRecords();

        List<RouteVO> datagrid = records.stream()
                .map(role -> {
                    RouteVO vo = new RouteVO();
                    CopyUtil.copyProperties(role, vo);
                    return vo;
                })
                .collect(Collectors.toList());

        List<String> routeIdList = datagrid.stream()
                .map(RouteVO::getId)
                .collect(Collectors.toList());

        if (routeIdList.isEmpty()) {
            return Result.successPage(datagrid, page.getTotal(), page.getCurrent(), page.getSize());
        }

        Map<String, List<RouteRoleDTO>> routeIdRoleMap = permRolePermissionMapper.listRouteRole(routeIdList)
                .parallelStream()
                .collect(Collectors.groupingBy(RouteRoleDTO::getRouteId));

        datagrid.forEach(vo -> {
            String routeId = vo.getId();
            List<RouteRoleDTO> routeRoleDTOS = routeIdRoleMap.getOrDefault(routeId, Collections.emptyList());
            vo.setRoles(routeRoleDTOS);
        });
        return Result.successPage(datagrid, page.getTotal(), page.getCurrent(), page.getSize());
    }

    @GetMapping("/api/route.lists")
    @ApiDocMethod(description = "路由列表1.2")
    Result listRoute2(RouteSearchParam param) {
        String serviceId = param.getServiceId();
        LambdaQueryWrapper<ConfigServiceRoute> wrapper = new QueryWrapper<ConfigServiceRoute>().lambda()
                .eq(StringUtils.isNotBlank(serviceId), ConfigServiceRoute::getServiceId, serviceId);
        List<ConfigServiceRoute> configServiceRoutes = configServiceRouteMapper.selectList(wrapper);
        return Result.success(configServiceRoutes);
    }

    @Api(name = "route.add")
    @ApiDocMethod(description = "新增路由")
    void addRoute(RouteAddParam param) {
        // TODO: 新增路由
    }

    @Api(name = "route.update")
    @ApiDocMethod(description = "修改路由")
    void updateRoute(RouteUpdateParam param) {
        this.updateRouteConfig(param);
    }

    @PostMapping("/api/route.status.update")
    @ApiDocMethod(description = "修改路由状态")
    Result updateRouteStatus(RouteStatusUpdateParam param) {
        String routeId = param.getId();
        ConfigServiceRoute configServiceRoute = configServiceRouteMapper.selectOne(new QueryWrapper<ConfigServiceRoute>().lambda().eq(ConfigServiceRoute::getId, routeId));
        if (Objects.isNull(configServiceRoute)) {
            return Result.fail("路由不存在");
        }
        configServiceRoute.setStatus(param.getStatus());
        int i = configServiceRouteMapper.updateById(configServiceRoute);
        if (i > 0) {
            this.sendMsg(configServiceRoute);
        }
        return Result.success();
    }

    @Api(name = "route.del")
    @ApiDocMethod(description = "删除路由")
    void delRoute(RouteDeleteParam param) {
        // TODO: 删除路由
    }


    private void updateRouteConfig(RouteUpdateParam routeUpdateParam) {
        String routeId = routeUpdateParam.getId();
        ConfigServiceRoute configRouteBase = configServiceRouteMapper.selectOne(new QueryWrapper<ConfigServiceRoute>().lambda().eq(ConfigServiceRoute::getId, routeId));
        boolean doSave = configRouteBase == null;
        if (doSave) {
            configRouteBase = new ConfigServiceRoute();
            configRouteBase.setId(routeId);
        }
        configRouteBase.setStatus(routeUpdateParam.getStatus().byteValue());

        int i = doSave ? configServiceRouteMapper.insert(configRouteBase)
                : configServiceRouteMapper.updateById(configRouteBase);

        if (i > 0) {
            this.sendMsg(configRouteBase);
        }
    }

    private void sendMsg(ConfigServiceRoute routeDefinition) {
        RouteConfigDto routeConfigDto = new RouteConfigDto();
        routeConfigDto.setRouteId(routeDefinition.getId());
        routeConfigDto.setStatus(routeDefinition.getStatus().intValue());
        routeConfigService.sendRouteConfigMsg(routeConfigDto);
    }

    @GetMapping("/api/route.role.get")
    @ApiDocMethod(description = "获取路由对应的角色", elementClass = RoleVO.class)
    Result getRouteRole(RouteSearchParam param) {
        if (StringUtils.isBlank(param.getId())) {
            throw ServiceInterruptionException.fail(500, "id不能为空");
        }
        List<RoleVO> routeRole = this.getRouteRole(param.getId());
        return Result.success(routeRole);
    }

    /**
     * 获取路由对应的角色
     *
     * @param routeIdList routeIdList
     * @return
     */
    private List<RoleVO> getRouteRole(List<String> routeIdList) {
        // key:routeId, value: roleCode
        LambdaQueryWrapper<PermRolePermission> wrapper = new QueryWrapper<PermRolePermission>().lambda().in(PermRolePermission::getRouteId, routeIdList);
        return permRolePermissionMapper.selectList(wrapper).stream()
                .map(permRolePermission -> {
                    RoleVO vo = new RoleVO();
                    String roleCode = permRolePermission.getRoleCode();
                    PermRole permRole = permRoleMapper.selectOne(new QueryWrapper<PermRole>().lambda().eq(PermRole::getRoleCode, roleCode));
                    BeanUtils.copyProperties(permRole, vo);
                    return vo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 获取路由对应的角色
     *
     * @param id routeId
     * @return
     */
    private List<RoleVO> getRouteRole(String id) {
        LambdaQueryWrapper<PermRolePermission> wrapper = new QueryWrapper<PermRolePermission>().lambda().eq(PermRolePermission::getRouteId, id);
        return permRolePermissionMapper.selectList(wrapper)
                .stream()
                .map(permRolePermission -> {
                    RoleVO vo = new RoleVO();
                    String roleCode = permRolePermission.getRoleCode();
                    PermRole permRole = permRoleMapper.selectOne(new QueryWrapper<PermRole>().lambda().eq(PermRole::getRoleCode, roleCode));
                    BeanUtils.copyProperties(permRole, vo);
                    return vo;
                })
                .collect(Collectors.toList());
    }

    @PostMapping("/api/route.role.update")
    @ApiDocMethod(description = "更新路由对应的角色")
    public Result updateRouteRole(RoutePermissionParam param) {
        RoutePermissionParam oldRoutePermission = this.buildOldRoutePermission(param.getRouteId());
        routePermissionService.updateRoutePermission(param);
        try {
            routePermissionService.sendRoutePermissionReloadMsg(oldRoutePermission);
        } catch (Exception e) {
            log.error("消息推送--路由权限(reload)失败", e);
            // 回滚
            routePermissionService.updateRoutePermission(oldRoutePermission);
            throw ServiceInterruptionException.fail(500, e.getMessage());
        }
        return Result.success();
    }

    private RoutePermissionParam buildOldRoutePermission(String routeId) {
        List<RoleVO> routeRole = this.getRouteRole(routeId);
        List<String> roleCodeList = routeRole.stream()
                .map(RoleVO::getRoleCode)
                .collect(Collectors.toList());
        RoutePermissionParam routePermissionParam = new RoutePermissionParam();
        routePermissionParam.setRouteId(routeId);
        routePermissionParam.setRoleCode(roleCodeList);
        return routePermissionParam;
    }

}
